from uuid import uuid4

from libvirt import libvirtError

from core.repositories._base import CRUDRepository
from core.services import get_vm_conn, db
from eve.models.libvirt_models.network import Network
from eve.models.virtual_machine_network import LibvirtNetwork, VirtualMachineNetwork
from eve.validators.virtual_machine_network import (
    VirtualMachineNetworkCreatingValidator as CreatingValidator,
    VirtualMachineNetworkPartialUpdatingValidator as PartialUpdatingValidator,
)


class VirtualMachineNetworkRepository(CRUDRepository):

    def get_model(self):
        return super().get_model().with_('libvirt_network')

    def create(self, payload: CreatingValidator):
        name = str(uuid4())
        forward_mode = LibvirtNetwork.FORWARD_MODE_TYPE(payload.libvirt_network.forward_mode_type).name
        network_xml = Network.build_network_xml(name, payload.libvirt_network.ip_address, forward_mode=forward_mode)
        client = get_vm_conn()
        conn = next(client)
        virNetwork = conn.networkDefineXML(network_xml)
        network = Network.from_xml(virNetwork.XMLDesc())

        with db.transaction():
            libvirt_network = LibvirtNetwork(network.to_model_dict())
            libvirt_network.save()
            d = payload.dict()
            d['libvirt_network_id'] = libvirt_network.id
            virtual_machine_network = VirtualMachineNetwork(d)
            virtual_machine_network.save()

        return virtual_machine_network

    def partial_update(self, id, payload: PartialUpdatingValidator):
        virtual_machine_network = VirtualMachineNetwork.find_or_fail(id)
        libvirt_network = virtual_machine_network.libvirt_network

        client = get_vm_conn()
        conn = next(client)
        virNetwork = conn.networkLookupByName(libvirt_network.name)
        network = Network.from_xml(virNetwork.XMLDesc())
        network.ip.address = payload.libvirt_network.ip_address
        network.ip.netmask = payload.libvirt_network.ip_netmask
        conn.networkDefineXML(network.to_xml())
        # cmd = f'''virsh net-update 24709870-3d13-4ca5-bcf0-aeb22e079cff modify ip "<ip address='192.168.160.1' />"'''
        # cmd = f'''modify ip "<ip address='192.168.160.1' netmask='255.255.255.0' />"'''
        # virNetwork.update(cmd)

        libvirt_network.update(payload.libvirt_network.dict())
        virtual_machine_network.update(payload.dict())

        return virtual_machine_network

    def delete(self, id):
        d = self.Model.find_or_fail(id)

        try:
            client = get_vm_conn()
            conn = next(client)
            virNetwork = conn.networkLookupByName(d.libvirt_network.name)
            r = virNetwork.undefine()
            d.delete()
        except libvirtError as e:
            raise e

        return d
